-- paquetage de base
with Ada.Text_IO, Ada.Integer_Text_IO;use Ada.Text_IO,Ada.Integer_Text_IO;

-- paquetages de gestion des exceptions
with Ada.Exceptions;use Ada.Exceptions;

-- interfasage avec le C
with Interfaces.C; use Interfaces.C;

-- paquetages de l'interface Homme Machine (gtk)
with Gtk.Window, Gtk.Enums, Gtk.Button, Gtk.Container, Gtk.Table, Gtk.Text_View, Gtk.Text_Buffer, Gtk.Label, Gtk.Widget,Gtk.Handlers, Gtk.Marshallers, Gtk.Scrolled_Window, Gtk.Text_Mark, Gtk.Text_Iter, Gtk.Image;
use Gtk.Window, Gtk.Enums, Gtk.Button, Gtk.Container, Gtk.Table, Gtk.Text_View, Gtk.Text_Buffer, Gtk.Label, Gtk.Widget,Gtk.Handlers, Gtk.Marshallers, Gtk.Scrolled_Window, Gtk.Text_Mark, Gtk.Text_Iter, Gtk.Image;

with GLib, GLib.Convert; use GLib, GLib.Convert;



package body Lib is

-------------------------------------------------------------------------------------------------------------------------------------------
--								TACHE FIXE
-------------------------------------------------------------------------------------------------------------------------------------------

-- Implementation du telephone fixe
	task body Fixe is

	-- Attribut standard qui pointe vers le PID du standard de l'environnement

		enPanne : boolean;

		monNum : GLib.Guint;

		enLigne : boolean;

		std : ptr_Standard;

		parent : ptr_Telephone;

		CONNEXION_FAILURE : exception;

		attente : Integer := 0;

		begin

			
			enPanne := false;
			enLigne := false;



			
			while(not(enPanne)) loop
				select
				----------------------------------------------------------------------------------
				-- Signalisation de l'appel entrant
					accept INIT(unNum : GLib.Guint; tel : ptr_Telephone; s : ptr_Standard)
					do
						std := s;
						parent := tel;
						put_line("bip bip bip");
						monNum := unNum;
					end INIT;

				----------------------------------------------------------------------------------
				or
				----------------------------------------------------------------------------------
				-- Le client decroche le combine
					accept DECROCHER
					do
						put_line("je decroche:");
						enLigne:=true;
					end DECROCHER;
				----------------------------------------------------------------------------------
				or
				----------------------------------------------------------------------------------
				-- Mettre fin a la conversation
					accept RACCROCHER(destinataire : in GLib.Guint)
					do
						put(Integer(monNum));
						put_line(" raccroche le telephone");
						enLigne := false;
						std.DECONNECTER(monNum, destinataire);
					end RACCROCHER;
				----------------------------------------------------------------------------------
				or
				----------------------------------------------------------------------------------
				-- Notifier au Standard que l'on veut appeller un numéros
					accept APPELER(destinataire : in GLib.Guint)
					do
					-- Si le telephone n'est pas deja en communication
					put(Integer(monNum));put(" appelle : ");put(Integer(destinataire));put_line(" maintenant");
						if (not(enLigne)) then
						-- Appel à la fonction connexion du Standard
-- 							if (CONNEXION(Integer(monNum),
-- 								Integer(destinataire))=-1) then
-- 								raise CONNEXION_FAILURE;
-- 							end if;
							enLigne := true;
							std.CONNECTER(monNum, destinataire);

					-- Sinon l'appelle n'est pas pris en compte
						else
							put_line("Telephone en cours de communication");
	
						end if;
					exception
					when E : others =>
						put_line("Erreur de connexion lors de l'appel");
						put("Exception Identity : ");
						put_line(Exception_Name(Exception_Identity(E)));
						put("Exception Name : ");
						put_line(Exception_Name(E));
						put("Exception message : ");
						put_line(Exception_Message(E));
						put("Exception information : ");
						put_line(Exception_Information(E));
					end APPELER;
				----------------------------------------------------------------------------------
				end select;
				put_line("je suis pas mort!");
			end loop;
			exception
			when E : others =>
				put_line("Erreur dans la tache Fixe");
				put("Exception Identity : ");
				put_line(Exception_Name(Exception_Identity(E)));
				put("Exception Name : ");
				put_line(Exception_Name(E));
				put("Exception message : ");
				put_line(Exception_Message(E));
				put("Exception information : ");
				put_line(Exception_Information(E));
		end Fixe;


-------------------------------------------------------------------------------------------------------------------------------------------
--								TACHE STANDARD
-------------------------------------------------------------------------------------------------------------------------------------------


	task body Standard is
	
	enPanne : boolean := false;
	annuaire : pages_jaunes;
	ctl : ptr_Central;
	PID:Integer;

	NUMERO_PAS_ATTRIBUE : exception;

	begin

		while(not(enPanne))loop
			select
				accept INIT(std : ptr_Standard; p : Integer; c : ptr_Central)
				do
					ctl := c; PID := p;
					for index in 0..getNbTel-1 loop
						Annuaire(index+1) := New Telephone;
						Telephone_New(Annuaire(index+1), GLib.Guint(getNumero(index)),std);
					end loop;
				end INIT;
				or
				accept CONNECTER(exp : GLib.Guint;dest : GLib.Guint )
				do
					-- rechercher si le destinataire existe (en C)
					if (estDansAnnuaire(Integer(dest),Integer(exp))/= -1) then
					-- si le destinataire existe alors demander
					-- au central d'etablir la connexion
						ctl.CONNECTER(getTelephone(annuaire,Integer(exp)),getTelephone(annuaire,Integer(dest)));
					-- sinon lever une exception
					else
						raise NUMERO_PAS_ATTRIBUE;
					end if;
				exception
				when E : NUMERO_PAS_ATTRIBUE =>
					put_line("Le numéros que vous avez composé n'est pas attribué");
				when E : others =>
					put_line("Erreur de connexion au niveau du standard");
				end CONNECTER;
				or
				accept DECONNECTER(exp : GLib.Guint;dest : GLib.Guint )
				do
					ctl.DECONNECTER(getTelephone(annuaire,Integer(exp)),getTelephone(annuaire,Integer(dest)));
	
					exception
					when E : others =>
					put_line("Communication deja coupee");
				end DECONNECTER;
			end select;
		end loop;
		exception
		when E : others =>
			put_line("Erreur dans la tache STANDARD");
			put("Exception Identity : ");
			put_line(Exception_Name(Exception_Identity(E)));
			put("Exception Name : ");
			put_line(Exception_Name(E));
			put("Exception message : ");
			put_line(Exception_Message(E));
			put("Exception information : ");
			put_line(Exception_Information(E));
	end Standard;

procedure Standard_New(std : in out ptr_Standard; c : ptr_Central) is
begin
	std := new Standard;
	std.INIT(std,Standard_Init,c);

end Standard_New;

function getTelephone(ann: in pages_jaunes;num : in integer) return ptr_Telephone is
NUMERO_NON_ATTRIBUE : exception;
begin
	for index in 0..getNbTel-1 loop
		if (ann(index+1).monNumero = num) then
			return ann(index+1);
		end if;
	end loop;
	raise NUMERO_NON_ATTRIBUE;
	exception
		when E : NUMERO_NON_ATTRIBUE =>
			put_line("Le numero que vous avez compose n'est pas attribue");
			put("Exception Identity : ");
			put_line(Exception_Name(Exception_Identity(E)));
			put("Exception Name : ");
			put_line(Exception_Name(E));
			put("Exception message : ");
			put_line(Exception_Message(E));
			put("Exception information : ");
			put_line(Exception_Information(E));
end getTelephone;
-------------------------------------------------------------------------------------------------------------------------------------------
--								TACHE CENTRAL
-------------------------------------------------------------------------------------------------------------------------------------------

task body Central is

	enPanne : boolean := false;

	OCCUPE : exception;
	ABSENT : exception;

begin
	while(not(enPanne)) loop

		select

			accept CONNECTER( exp: ptr_Telephone; dest: ptr_Telephone )
			do
				-- Si le correspondant n'est pas en ligne
				if (dest.enLigne = false) then
					--if(Attendre_decrocher(dest.monNum)/=-1) then
					Signaler_Appel(dest);
					--Mettre_en_relation(dest,exp);
					--Mettre_en_relation(exp,dest);
				else
					raise OCCUPE;
				end if;

			exception
				when E : OCCUPE =>
					Afficher(exp,"Votre correspondant est déjà en ligne, veuillez rappeler plus tard");
				when E : ABSENT =>
					Afficher(exp,"Votre correspondant n'est pas la pour le moment, veuillez rappeler ultérieurement");
			end CONNECTER;

			or

			accept DECONNECTER( exp: ptr_Telephone; dest: ptr_Telephone )
			do
				--Couper_Communication(dest,exp);
				Couper_Communication(exp,dest);

			end DECONNECTER;

		end select;

	end loop;

end Central;

-------------------------------------------------------------------------------------------------------------------------------------------
--								TELEPHONE
-------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------
--                 IHM Configuration                       --
-------------------------------------------------------------


procedure Telephone_New(tel: ptr_Telephone;unNum : in GLib.Guint; std : in ptr_Standard) is


	min : GLib.Gdouble := 1.0;
	max : GLib.Gdouble := 100000.0;

begin

	tel.fixe := new Fixe;
	tel.correspondant := new Telephone;
	tel.fixe.INIT(unNum, tel, std);
	tel.monNumero := integer(unNum);

	tel.std := std;

	Gtk.Window.Gtk_New(tel.telephone);
	Gtk.Button.Gtk_New(tel.b_appeler,"Decrocher");
	Gtk.Button.Gtk_New(tel.b_parler,"Parler");
	Set_Sensitive(tel.b_parler,false);

	Gtk.Spin_Button.Gtk_New(tel.ecran,min,max,min);

	Gtk.Text_View.Gtk_New(tel.msg_entrant);
	Set_Editable(tel.msg_entrant,false);Set_Cursor_Visible(tel.msg_entrant,false);Set_Sensitive(tel.msg_entrant,false);
	Gtk.Text_View.Gtk_New(tel.msg_sortant);

	Gtk.Table.Gtk_New(tel.t_fond,4,4,true);

	Gtk.Image.Gtk_New(tel.img_enLigne,"pas_en_ligne.gif");

	Gtk.Container.Add(Gtk.Container.Gtk_Container(tel.telephone),tel.t_fond);
	Gtk.Table.Attach(tel.t_fond, tel.ecran,0,3,3,4);
	Gtk.Table.Attach(tel.t_fond, tel.b_appeler, 3,4,3,4);
	Gtk.Table.Attach(tel.t_fond, tel.b_parler, 3,4,2,3);
	Gtk.Table.Attach(tel.t_fond, tel.msg_entrant, 0,3,0,2);
	Gtk.Table.Attach(tel.t_fond, tel.img_enLigne, 3,4,0,2);
	Gtk.Table.Attach(tel.t_fond, tel.msg_sortant, 0,3,2,3);

	Gtk.Window.Show_All(tel.telephone);
	Gtk.Window.Set_Title(tel.telephone,"Telephone");

	Telephone_Callback.Connect
		(tel.b_appeler, "clicked",
		Telephone_Callback.To_Marshaller (Action_Appeler'Access),
		tel);
	Telephone_Callback.Connect
		(tel.b_parler, "clicked",
		Telephone_Callback.To_Marshaller (Action_Parler'Access),
		tel);
end Telephone_New;

procedure Signaler_Appel(tel : ptr_Telephone) is

begin
	Gtk.Image.Set(tel.img_enLigne,"appel_entrant.gif");
	tel.appel_entrant := true;
end Signaler_Appel;

procedure Action_Appeler (Button: access Gtk.Widget.Gtk_Widget_Record'Class; tel : ptr_Telephone)is
   begin

	-- Si Appel entrant
	if (tel.appel_entrant = true) then
		tel.enLigne := true;
		Set_Sensitive(tel.b_parler,true);Set(tel.img_enLigne,"en_ligne.gif");
		tel.appel_entrant := false;
		Set_Label(tel.b_appeler,"Raccrocher");
	else
		if (not(tel.enLigne)) then
		-- Si le telephone n'est pas en ligne
			Set_Sensitive(tel.b_parler,true);Set(tel.img_enLigne,"en_ligne.gif");
			Set_Label(tel.b_appeler,"Raccrocher");
			tel.enLigne := true;
			tel.fixe.APPELER(Guint(Gtk.Spin_Button.Get_Value_As_Int(tel.ecran)));

		else
		-- Sinon on raccroche
			Set_Sensitive(tel.b_parler,false);
			Set(tel.img_enLigne,"pas_en_ligne.gif");
			Set_Label(tel.b_appeler,"Decrocher");
			tel.enLigne := false;
			tel.fixe.RACCROCHER(Guint(tel.correspondant.monNumero));

		end if;
	end if;
	exception
	when E : others =>
		put_line("Reseau indisponible");
		put("Exception Identity : ");
		put_line(Exception_Name(Exception_Identity(E)));
		put("Exception Name : ");
		put_line(Exception_Name(E));
		put("Exception message : ");
		put_line(Exception_Message(E));
		put("Exception information : ");
		put_line(Exception_Information(E));
		--tel.fixe := new Fixe;
		--tel.fixe.INIT(Guint(tel.monNumero), tel, tel.std);
   end Action_Appeler;

procedure Action_Parler (Button: access Gtk.Widget.Gtk_Widget_Record'Class; tel : ptr_Telephone)is

Buffer : Gtk_Text_Buffer;
Start : Gtk_Text_Iter;
The_End : Gtk_Text_Iter;
   begin
	Buffer := Get_Buffer(tel.msg_sortant);
	Get_Bounds  (Buffer, Start, The_End);
	Afficher(tel.correspondant,Locale_From_UTF8(Gtk.Text_Buffer.Get_Text(Buffer,Start,The_End)));

	exception
	when E : others =>
		put_line("Reseau indisponible");
		put("Exception Identity : ");
		put_line(Exception_Name(Exception_Identity(E)));
		put("Exception Name : ");
		put_line(Exception_Name(E));
		put("Exception message : ");
		put_line(Exception_Message(E));
		put("Exception information : ");
		put_line(Exception_Information(E));
   end Action_Parler;

procedure Mettre_en_relation(tel: ptr_Telephone; correspondant : ptr_Telephone) is
begin
	tel.correspondant := correspondant;
	Set_Sensitive(correspondant.b_parler,true);
	Set(correspondant.img_enLigne,"en_ligne.gif");
end Mettre_en_relation;

procedure Couper_Communication(tel: ptr_Telephone; correspondant : ptr_Telephone) is
begin
	tel.correspondant := null;
	correspondant.correspondant := null;
	Set_Sensitive(correspondant.b_parler,false);
	Set_Sensitive(tel.b_parler,false);
	Set(correspondant.img_enLigne,"pas_en_ligne.gif");
	Set(tel.img_enLigne,"pas_en_ligne.gif");
end Couper_Communication;

procedure Afficher(tel: ptr_Telephone; msg : in String) is
begin
	Set_Text(Get_Buffer(tel.msg_entrant),msg);
end Afficher;
-------------------------------------------------------------


end Lib;
